<?php

require_once("curl_http_client.php");

class VTWebservicesException extends Exception {
    
}

class VTWebservices {
    function __construct($serviceUrl, $username, $accessKey) {
        $this->serviceUrl = $serviceUrl;
        $this->username = $username;
        $this->accessKey = $accessKey;
    }

    /**
     * Log into vtiger.
     * @throws VTWebservicesException if the login fails.
     */
    function login() {
        $response = $this->doGet(array('operation' => 'getchallenge', 'username' => $this->username));
        if ($response['success'] == true) {
            $token = $response['result']['token'];
            $encodedKey = md5($token . $this->accessKey);
            $response = $this->doPost(array('operation' => 'login',
                        'username' => $this->username, 'accessKey' => $encodedKey));
            if ($response['success'] == true) {
                $this->sessionId = $response['result']['sessionName'];
                $this->userId = $response['result']['userId'];
            } else {
                throw new VTWebservicesException("Failed to login: " . $response['error']["errorMsg"]);
            }
        } else {
            throw new VTWebservicesException("Failed to login: " . $response['error']["errorMsg"]);
        }
    }

    /**
     * Log out of vtiger.
     */
    function logout() {
        $this->post('logout', array());
    }

    /**
     * List the types the user can access
     *
     * @return An array of names of vtiger types.
     */
    function listTypes() {
        $result = $this->get('listtypes', array());
        return $result['types'];
    }

    /**
     * Describe a vtiger type.
     * @param $name The name of the type to describe
     * @return An array containing the description information.
     */
    function describe($name) {
        return $this->get('describe', array('elementType' => $name));
    }

    /**
     * Create a vtiger oject
     * @param $object An array containing fieldnames mapped to their values
     * @param $objectType The type of the object to create.
     */
    function create($object, $objectType) {

        if (!isset($object['assigned_user_id']) || $object['assigned_user_id'] == null) {
            $object['assigned_user_id'] = $this->userId;
        }
        $objectJson = json_encode($object);
        return $this->post('create', array('elementType' => $objectType,
            'element' => $objectJson));
    }

    /**
     * Retrieve a vtiger object
     *
     * @param id The id of the object to retrieve.
     * @return The contents of the object as an Array.
     */
    function retrieve($id) {
        return $this->get('retrieve', array('id' => $id));
    }

    /**
     * Update an existing vtiger object
     * 
     * @param $object An Array representing the object to update. 
     * 	It must contain an id field which will be used to look up the original object
     */
    function update($object) {
        $objectJson = json_encode($object);
        return $this->post('update', array('element' => $objectJson));
    }

    /**
     * Delete an existing vtiger object
     *
     * @param $id The id of the object to delete.
     */
    function delete($id) {
        return $this->post('delete', array('id' => $id));
    }

    /**
     * Execute a query
     *
     * @param $query The query to exectue
     */
    function query($query) {
        return $this->get('query', array('query' => $query));
    }

    function get($operation, $parameters) {
        $response = $this->doGet(array_merge($parameters, array('operation' => $operation, 'sessionName' => $this->sessionId)));
        if ($response['success'] == true) {
            return $response['result'];
        } else {
            throw new VTWebservicesException("Failed to $operation: " . $response['error']["errorMsg"]);
        }
    }

    function post($operation, $parameters) {
        $response = $this->doPost(array_merge($parameters, array('operation' => $operation, 'sessionName' => $this->sessionId)));
        if ($response['success'] == true) {
            return $response['result'];
        } else {
            throw new VTWebservicesException("Failed to $operation: " . $response['error']["message"]);
        }
    }

    function doGet($params) {
        $arr = array();
        foreach ($params as $name => $value) {
            $arr[] = $name . '=' . urlencode($value);
        }
        $url = $this->serviceUrl . '?' . implode("&", $arr);

        $httpc = new Curl_HTTP_Client();
        $response = $httpc->fetch_url($url);
        return json_decode($response, true);
    }

    function doPost($params) {
        $httpc = new Curl_HTTP_Client();
        $response = $httpc->send_post_data($this->serviceUrl, $params);
        return json_decode($response, true);
    }

}